#pragma once
#include <string>
#include <memory>
#include <nice2d/predef.h>

#define RUNTIME_METAOBJECT(object)\
(MetaObject*)(&object::metaObject##object)

#define DECLARE_OBJECT(object)\
public:\
    static  const MetaObject metaObject##object;\
    virtual const MetaObject* getMetaObject()const override;\
    virtual std::string getObjectName()const override;

#define DECLARE_ABSTRACT_OBJECT(object)\
public:\
    static  const MetaObject metaObject##object;\
    virtual const MetaObject* getMetaObject()const;\
    virtual std::string getObjectName()const;

#define IMPLEMENT_BASE_OBJECT(object)\
const MetaObject object::metaObject##object(#object,NULL,sizeof(object));\
    inline const MetaObject* object::getMetaObject()const\
{\
    return RUNTIME_METAOBJECT(object);\
}\
    inline std::string object::getObjectName()const\
{\
    return getMetaObject()->name();\
}

#define IMPLEMENT_OBJECT(object,parent)\
const MetaObject object::metaObject##object(#object,RUNTIME_METAOBJECT(parent),sizeof(object));\
    const MetaObject* object::getMetaObject()const\
{\
    return  RUNTIME_METAOBJECT(object);\
}\
    std::string object::getObjectName()const\
{\
    return  getMetaObject()->name();\
}

class MetaObject
{
public:
    MetaObject(const std::string &name,const MetaObject* parent,uint32_t size);
    ~MetaObject();
public:
    std::string name()const;
    uint32_t diskUsed()const;

    bool isExactly(const MetaObject& type)const;
    bool isDerived(const MetaObject& type)const;

    static const MetaObject* first();
    const MetaObject* next()const;
    const MetaObject* parent()const;
    static const MetaObject* metaObjectByObjectName(const std::string& objectname);
private:
    std::unique_ptr<class MetaObjectData> data;
};
